import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class IDGenerator {
    private Integer id = 0;
    private static volatile IDGenerator instance;

    private IDGenerator() {}

    public static IDGenerator getInstance() {
        if (instance == null) {
            synchronized (IDGenerator.class) {
                if (instance == null) {instance = new IDGenerator();}
            }
        }
        return instance;
    }

    public int getId() {synchronized (this) {return ++this.id;}}
}

public class SynchronizedDemo {
    public static void main(String[] args) throws InterruptedException {
        List<Integer> list = new ArrayList();
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        for (int j = 0; j < 100; ++j) {
            for (int i = 0; i < 100; ++i) {
                executorService.execute(() -> {
                    synchronized (list) {list.add(IDGenerator.getInstance().getId());}
                });
            }
        }

        //Close the thread pool and no longer accept new tasks
        executorService.shutdown();
        //Wait for all tasks to complete, up to 30 seconds
        executorService.awaitTermination(30, TimeUnit.SECONDS);

        //System.out.println(Arrays.toString(list.toArray()));
        System.out.println(list.size());
        System.out.println(list.stream().max(Integer::compareTo).get());
    }
}